﻿//-----------------------------------------------------------------------
// <copyright file="PlanViewModelTest.cs" company="Microsoft">
//     Copyright (c) AGALTIER, Microsoft. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace ArchiSimple.Windows.Test.ViewModel
{
    using System;
    using System.Linq;
    using ArchiSimple.Windows.ViewModel;
    using ArchiSimple.Windows.Model;
    using ArchiSimple.Windows.ViewModel.PlanObjects;
    using System.Windows.Media;
    using Xunit;

    /// <summary>
    /// TODO: Provide summary section in the documentation header.
    /// </summary>
    public class PlanViewModelTest
    {
        [Fact]
        public void SnapValueTest()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);

                double x = 152;
                double y = 251;

                viewModel.SnapValue(ref x, ref y);

                Assert.Equal(152, x);
                Assert.Equal(251, y);
            }
        }

        [Fact]
        public void SnapValueTest_ToPoint()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                var point = new Point() { X = 145, Y = 255 };
                viewModel.AddToPlan(viewModel.CreateOrGet(point));


                double x = 152;
                double y = 251;

                viewModel.SnapValue(ref x, ref y);

                Assert.Equal(145, x);
                Assert.Equal(255, y);

                x = 156;
                y = 251;

                viewModel.SnapValue(ref x, ref y);

                Assert.Equal(156, x);
                Assert.Equal(251, y);
            }
        }

        /// <summary>
        /// </summary>
        [Fact]
        public void MovePointTest_WithSnap()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(0, 0, 100, 0);

                viewModel.AddWall(100, 0, 100, 100);

                viewModel.MovePoint(viewModel.PlanObjects[2] as PointViewModel, 103, 50);

                Assert.Equal(5, viewModel.PlanObjects.Count);
                Assert.IsType(typeof(WallViewModel), viewModel.PlanObjects[0]);
                Assert.IsType(typeof(PointViewModel), viewModel.PlanObjects[1]);
                Assert.IsType(typeof(PointViewModel), viewModel.PlanObjects[2]);
                Assert.IsType(typeof(WallViewModel), viewModel.PlanObjects[3]);
                Assert.IsType(typeof(PointViewModel), viewModel.PlanObjects[4]);
                Assert.Equal(0, (viewModel.PlanObjects[1] as PointViewModel).X);
                Assert.Equal(0, (viewModel.PlanObjects[1] as PointViewModel).Y);
                Assert.Equal(100, (viewModel.PlanObjects[2] as PointViewModel).X);
                Assert.Equal(50, (viewModel.PlanObjects[2] as PointViewModel).Y);
                Assert.Equal(100, (viewModel.PlanObjects[4] as PointViewModel).X);
                Assert.Equal(100, (viewModel.PlanObjects[4] as PointViewModel).Y);

                viewModel.MovePoint(viewModel.PlanObjects[2] as PointViewModel, 103, 3);

                Assert.Equal(0, (viewModel.PlanObjects[1] as PointViewModel).X);
                Assert.Equal(0, (viewModel.PlanObjects[1] as PointViewModel).Y);
                Assert.Equal(100, (viewModel.PlanObjects[2] as PointViewModel).X);
                Assert.Equal(0, (viewModel.PlanObjects[2] as PointViewModel).Y);
                Assert.Equal(100, (viewModel.PlanObjects[4] as PointViewModel).X);
                Assert.Equal(100, (viewModel.PlanObjects[4] as PointViewModel).Y);
            }
        }

        /// <summary>
        /// Test if the drawing room is updated when a point is move.
        /// </summary>
        [Fact]
        public void MovePointTest_WithRoom()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(0, 0, 100, 0);
                viewModel.AddWall(100, 0, 100, 100);
                viewModel.AddWall(100, 100, 0, 100);
                viewModel.AddWall(0, 100, 0, 0);

                Assert.Equal(9, viewModel.PlanObjects.Count);

                var room = (viewModel.PlanObjects[8] as RoomViewModel);
                var geometry = room.ZoneGeometry;

                viewModel.MovePoint(viewModel.PlanObjects[2] as PointViewModel, 200, 50);

                Assert.Equal(200, (viewModel.PlanObjects[2] as PointViewModel).X);
                Assert.Equal(50, (viewModel.PlanObjects[2] as PointViewModel).Y);


                Assert.True(anyPointInGeometry(geometry, 0, 0));
                Assert.True(anyPointInGeometry(geometry, 200, 50));
                Assert.True(anyPointInGeometry(geometry, 100, 100));
                Assert.True(anyPointInGeometry(geometry, 0, 100));
            }
        }

        private bool anyPointInGeometry(PathGeometry geometry, int x, int y)
        {
            var figure = geometry.Figures[0] as PathFigure;

            if (figure.StartPoint.X == x && figure.StartPoint.Y == y)
            {
                return true;
            }

            var segment = figure.Segments[0] as PolyLineSegment;

            return segment.Points.Any(p => p.X == x && p.Y == y);
        }

        [Fact]
        public void MovePoint()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(0, 0, 100, 100);

                var endPoint = viewModel.PlanObjects[2] as PointViewModel;

                Assert.Equal(100, endPoint.Current.X);
                Assert.Equal(100, endPoint.Current.Y);

                viewModel.MovePoint(endPoint, 101, 99);
                Assert.Equal(101, endPoint.Current.X);
                Assert.Equal(99, endPoint.Current.Y);

                viewModel.MovePoint(endPoint, 105, 104);
                Assert.Equal(105, endPoint.Current.X);
                Assert.Equal(104, endPoint.Current.Y);
            }
        }

        [Fact]
        public void MoveRoom()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(10, 10, 100, 10);
                viewModel.AddWall(100, 10, 100, 100);
                viewModel.AddWall(100, 100, 10, 100);
                viewModel.AddWall(10, 100, 10, 10);

                var room = viewModel.PlanObjects.OfType<RoomViewModel>().First();

                Assert.Equal(10, room.Zone.X);
                Assert.Equal(10, room.Zone.Y);
                Assert.Equal(90, room.Zone.Width);
                Assert.Equal(90, room.Zone.Height);

                viewModel.MovePoint(room, 100, 200);

                Assert.Equal(110, room.Points[0].X);
                Assert.Equal(300, room.Points[0].Y);
                Assert.Equal(200, room.Points[1].X);
                Assert.Equal(300, room.Points[1].Y);
                Assert.Equal(200, room.Points[2].X);
                Assert.Equal(210, room.Points[2].Y);
                Assert.Equal(110, room.Points[3].X);
                Assert.Equal(210, room.Points[3].Y);

                Assert.Equal(110, room.Zone.X);
                Assert.Equal(210, room.Zone.Y);
                Assert.Equal(90, room.Zone.Width);
                Assert.Equal(90, room.Zone.Height);
            }
        }

        [Fact]
        public void SnapToWall()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(0, 0, 100, 100);

                viewModel.MousePoint = new System.Windows.Point(55, 45);

                Assert.Equal(50, viewModel.MouseX);
                Assert.Equal(50, viewModel.MouseY);
                Assert.True(viewModel.IsSnap);
            }
        }

        [Fact]
        public void SnapToWall2()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(0, 0, 100, 50);

                viewModel.MousePoint = new System.Windows.Point(50, 25);

                Assert.Equal(50, viewModel.MouseX);
                Assert.Equal(25, viewModel.MouseY);
                Assert.True(viewModel.IsSnap);
            }
        }

        [Fact]
        public void SnapToWall3()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(0, 10, 100, 110);

                viewModel.MousePoint = new System.Windows.Point(60, 70);

                Assert.Equal(60, viewModel.MouseX);
                Assert.Equal(70, viewModel.MouseY);
                Assert.True(viewModel.IsSnap);
            }
        }

        [Fact]
        public void SnapToWall4()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(0, 100, 100, 100);

                viewModel.MousePoint = new System.Windows.Point(50, 95);

                Assert.Equal(50, viewModel.MouseX);
                Assert.Equal(100, viewModel.MouseY);
                Assert.True(viewModel.IsSnap);
            }
        }

        [Fact]
        public void SnapToWall5()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(100, 0, 100, 100);

                viewModel.MousePoint = new System.Windows.Point(95, 50);

                Assert.Equal(100, viewModel.MouseX);
                Assert.Equal(50, viewModel.MouseY);
                Assert.True(viewModel.IsSnap);
            }
        }

        [Fact]
        public void NoSnapToWall()
        {
            using (new LocatorContext())
            {
                var viewModel = Locator.Locate<PlanViewModel>(null);
                viewModel.Init();
                viewModel.LoadPlanMessage(new Message.LoadPlanMessage { Plan = new Plan() });

                viewModel.AddWall(0, 0, 100, 100);

                viewModel.MousePoint = new System.Windows.Point(125, 115);

                Assert.Equal(125, viewModel.MouseX);
                Assert.Equal(115, viewModel.MouseY);
                Assert.False(viewModel.IsSnap);
            }
        }
    }
}
